package com.nanbei.lock;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.StampedLock;

/**
 * @ClassDescription: 邮戳锁
 * @JdkVersion: 1.8
 * @Author: libs
 * @Created: 2024/11/6 13:51
 */
public class StampedLockDemo {
    static StampedLock stampedLock = new StampedLock();
    static String text = "";

    static void write() {
        long stamp = stampedLock.writeLock();
        try {
            System.out.println(Thread.currentThread().getName() + "\t" + "进入写锁，开始写数据");
            text = "窗前明月光";
            System.out.println(Thread.currentThread().getName() + "\t" + "数据写完");
        } finally {
            stampedLock.unlockWrite(stamp);
        }

    }

    // 传统读锁，在读取数据的时候禁止写数据
    static void read() {
        long stamp = stampedLock.readLock();
        try {
            System.out.println(Thread.currentThread().getName() + "\t" + "进入读锁，开始读取数据");
            for (int i = 0; i < 4; i++) {
                try {
                    TimeUnit.SECONDS.sleep(1);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getName() + "\t" + "正在读取数据.....");
            }
            System.out.println(Thread.currentThread().getName() + "\t" + "读取到的数据为:" + text);
        } finally {
            stampedLock.unlockRead(stamp);
        }
    }

    // 乐观读，在读的时候如果遇到的写数据 乐观读就会变为悲观读
    static void optimisticRead() {
        long stamp = stampedLock.tryOptimisticRead();

        System.out.println(Thread.currentThread().getName() + "\t" + "进入读锁，开始读取数据");
        for (int i = 0; i < 4; i++) {
            try {
                TimeUnit.SECONDS.sleep(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName() + "\t" + "正在读取数据....." + stampedLock.validate(stamp));
        }
        // stampedLock.validate(stamp) 如果为false，代表在读取数据的时候又有新的数据写入
        // 乐观读就会变为悲观读
        if (!stampedLock.validate(stamp)) {
            stamp = stampedLock.readLock();
            try {
                System.out.println(Thread.currentThread().getName() + "\t" + "读取到的数据为:" + text);
            } finally {
                stampedLock.unlockRead(stamp);
            }
        } else {
            System.out.println(Thread.currentThread().getName() + "\t" + "读取到的数据为:" + text);
        }


    }

    public static void main(String[] args) {
        new Thread(StampedLockDemo::optimisticRead, "read").start();
        try {
            TimeUnit.SECONDS.sleep(1);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        new Thread(StampedLockDemo::write, "write").start();
    }
}
